﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using lycServo.cache;
using lycServo.client;
using lycServo.dao;
using lycServo.entity;
using lycServo.utils;

namespace lycServo.handler
{
    public class ListenHandler
    {
        private string _unitNo;
        private Action<string, string, string> _showMessage;
        private JudgeHandler _judgeHandler;
        private readonly object _lock = new object();
        public ListenHandler(string unitNo, Action<string, string, string> showMessage)
        {
            _unitNo = unitNo;
            _showMessage = showMessage;
            _judgeHandler = new JudgeHandler(unitNo, showMessage);
        }

        public void StartListening()
        {
            //根据unitNo加载属于自己的相关信息
            LoadInfo();
            //获取属于该设备的master
            if (!GlobalCachePool.client_dict.TryGetValue(_unitNo, out OmronClient client))
            {
                return;
            }
            //开始循环监听...
            List<PlcItemEntity> updateItems = new List<PlcItemEntity>();
            while (true)
            {
                updateItems.Clear();
                if (!client.HasStarted())
                {
                    Thread.Sleep(10 * 1000);
                    continue;
                }
                lock (_lock)
                {
                    try
                    {
                        if (GlobalCachePool.plcItems_dict.TryGetValue(_unitNo, out List<PlcItemEntity> items))
                        {
                            foreach (PlcItemEntity item in items)
                            {
                                string value = client.ReadData(item.ITEM_NO, item.DATA_LEN);
                                //判断与旧值是否相同
                                if (value.Equals(item.ITEM_VALUE))
                                {
                                    continue;
                                }

                                ShowMessage("0", $"[{item.ITEM_NO}]当前值[{value}]");

                                item.OLD_VALUE = item.ITEM_VALUE;
                                item.ITEM_VALUE = value;
                                item.UPDATE_DATE = DateTime.Now;
                                //将全局的单值信息更新
                                GlobalCachePool.single_plcItem_dict[item.ITEM_NO] = item;

                                updateItems.Add(item);
                            }
                            if (updateItems.Count > 0)
                            {
                                DBFactory.BatchUpdateOfItem(updateItems);
                            }
                            //一次扫描循环结束后再进行事件判定
                            _judgeHandler.JudgeEventByCache();
                        }
                    }
                    catch (Exception ex)
                    {
                        ShowMessage("listen_error", ex.Message);
                    }
                }
                Thread.Sleep(3000);
            }
        }

        /// <summary>
        /// 装载该UNIT的信息
        /// </summary>
        private void LoadInfo()
        {
            string itemSql = $"SELECT * FROM PLC_ITEM WHERE UNIT_NO='{_unitNo}'";
            List<PlcItemEntity> itemByUnit = DBFactory.QueryList<PlcItemEntity>(itemSql);

            if (itemByUnit.Count > 0)
            {
                ShowMessage("0", $"设备[{_unitNo}]加载[PLC_ITEM]数量[{itemByUnit.Count}]");
                try
                {
                    GlobalCachePool.plcItems_dict.Add(_unitNo, itemByUnit);
                    foreach (PlcItemEntity item in itemByUnit)
                    {
                        ServoUtils.InitPlcItem(item);
                    }
                }
                catch (Exception ex)
                {
                    ShowMessage("0", $"信号点加载异常!causeBy{ex.Message}");
                }
            }
            //开启设备连接(根据设备的PLC_NO建立不同的设备连接)
            if (GlobalCachePool.single_unit_dict.TryGetValue(_unitNo, out PlcUnitEntity unit))
            {
                //ModBus协议则启动ModBus客户端
                OmronClient omrClient = new OmronClient(_unitNo, unit.HOST, unit.PORT, _showMessage);
                GlobalCachePool.client_dict.Add(unit.UNIT_NO, omrClient);
                omrClient.Start();
            }

        }

        /// <summary>
        /// 监听设备信号点手动修改
        /// </summary>
        public void ListenChange()
        {
            string changeSql = $"SELECT * FROM PC_ITEM WHERE UNIT_NO='{_unitNo}' AND STATUS>0";

            while (true)
            {
                List<PcItemEntity> changeItems = DBFactory.QueryList<PcItemEntity>(changeSql);
                if (changeItems.Count == 0)
                {
                    Thread.Sleep(2000);
                    continue;
                }

                foreach (PcItemEntity item in changeItems)
                {
                    if (GlobalCachePool.client_dict.TryGetValue(item.UNIT_NO, out OmronClient client))
                    {
                        ShowMessage("0", $"WCS将[{item.ITEM_NO}]的值修改为[{item.ITEM_VALUE}]");
                        short data = Convert.ToInt16(item.ITEM_VALUE);
                        try
                        {
                            if (client.HasStarted())
                            {
                                client.WriteData(item.ITEM_NO, data);
                            }
                        }
                        catch (Exception ex)
                        {
                            ShowMessage("change_error", $"修改PLC点信息异常!causeBy:{ex.Message}");
                        }
                    }
                    //将状态改为0
                    //无论是否成功都将值重置为0
                    item.STATUS = 0;
                    item.ITEM_VALUE = "";
                    item.UPDATE_DATE = DateTime.Now;
                }

                DBFactory.BatchUpdateOfPc(changeItems);
                Thread.Sleep(2000);
            }
        }

        private void ShowMessage(string code, string message)
        {
            _showMessage?.Invoke(_unitNo, code, message);
        }
    }
}
